"""
学习路径推荐模块
基于用户画像和知识图谱生成个性化学习路径
支持Redis和MySQL混合存储
"""
from typing import Dict, List, Any
import json
from app.core.cache import cache_manager
from app.schemas.schemas import LearningPathStage
from app.models.models import SessionLocal, UserProfile, UserProgress
from sqlalchemy.orm import Session
from app.core.knowledge_graph import knowledge_graph

class LearningPathRecommendation:
    """学习路径推荐系统"""
    
    def __init__(self):
        """初始化推荐系统"""
        pass
    
    def _get_db_session(self) -> Session:
        """获取数据库会话"""
        return SessionLocal()
    
    def analyze_user_profile(self, user_id: str) -> Dict[str, Any]:
        """
        分析用户画像
        优先从缓存获取，如果没有则从数据库获取
        
        Args:
            user_id: 用户ID
            
        Returns:
            用户画像数据
        """
        # 尝试从缓存获取用户偏好
        user_preference = cache_manager.get_long_term_preference(user_id)
        
        if user_preference:
            return {
                "user_id": user_id,
                "knowledge_level": user_preference.get("knowledge_level", "beginner"),
                "learning_style": user_preference.get("learning_style", "visual"),
                "interests": user_preference.get("interests", []),
                "progress": user_preference.get("progress", {})
            }
        
        # 如果缓存中没有，则从数据库获取
        db = self._get_db_session()
        try:
            # 获取用户画像
            profile = db.query(UserProfile).filter(UserProfile.user_id == user_id).first()
            # 获取用户进度
            progress_records = db.query(UserProgress).filter(UserProgress.user_id == user_id).all()
            
            user_data = {
                "user_id": user_id,
                "knowledge_level": "intermediate",
                "learning_style": "visual",
                "interests": ["math", "science"],
                "progress": {}
            }
            
            if profile:
                user_data["knowledge_level"] = profile.knowledge_level
                user_data["learning_style"] = profile.learning_style
                user_data["interests"] = json.loads(profile.interests) if profile.interests else []
            
            if progress_records:
                user_data["progress"] = {
                    record.subject: float(record.progress) for record in progress_records
                }
            
            # 更新缓存
            cache_data = {
                "knowledge_level": user_data["knowledge_level"],
                "learning_style": user_data["learning_style"],
                "interests": user_data["interests"],
                "progress": user_data["progress"]
            }
            cache_manager.set_long_term_preference(user_id, cache_data)
            
            return user_data
        finally:
            db.close()
    
    def generate_learning_path(self, user_id: str, subject: str) -> List[LearningPathStage]:
        """
        生成个性化学习路径（复杂算法版本）
        
        Args:
            user_id: 用户ID
            subject: 学科
            
        Returns:
            学习路径列表
        """
        # 分析用户画像
        user_profile = self.analyze_user_profile(user_id)
        
        # 获取学科知识图谱
        knowledge_graph_data = self._get_subject_knowledge_graph(subject)
        
        # 根据多因素计算推荐权重
        recommended_path = self._calculate_personalized_path_with_kg(
            user_profile, 
            knowledge_graph_data, 
            subject
        )
        
        return recommended_path
    
    def _get_subject_knowledge_graph(self, subject: str) -> Dict[str, Any]:
        """
        获取学科知识图谱
        
        Args:
            subject: 学科名称
            
        Returns:
            知识图谱数据
        """
        return knowledge_graph.get_subject_knowledge_graph(subject)
    
    def _calculate_personalized_path_with_kg(self, user_profile: Dict, knowledge_graph: Dict, subject: str) -> List[LearningPathStage]:
        """
        结合知识图谱计算个性化学习路径
        
        Args:
            user_profile: 用户画像
            knowledge_graph: 学科知识图谱
            subject: 学科
            
        Returns:
            个性化学习路径
        """
        # 1. 基于用户知识水平调整难度权重
        knowledge_level_weight = self._get_knowledge_level_weight(user_profile["knowledge_level"])
        
        # 2. 基于学习风格调整内容类型权重
        learning_style_weight = self._get_learning_style_weight(user_profile["learning_style"])
        
        # 3. 基于用户兴趣调整主题权重
        interest_weight = self._get_interest_weight(user_profile["interests"], subject)
        
        # 4. 基于学习进度调整内容选择
        progress_weight = self._get_progress_weight(user_profile["progress"], subject)
        
        # 5. 综合权重计算
        final_weights = {
            "knowledge_level": knowledge_level_weight,
            "learning_style": learning_style_weight,
            "interest": interest_weight,
            "progress": progress_weight
        }
        
        # 6. 基于知识图谱查找合适的路径
        # 查找用户已掌握知识点
        mastered_points = self._get_mastered_knowledge_points(user_profile["progress"])
        
        # 在知识图谱中查找合适的学习路径
        learning_path_nodes = self._find_suitable_path(
            knowledge_graph, 
            mastered_points, 
            knowledge_level_weight
        )
        
        # 7. 将知识点转换为学习路径阶段
        learning_path = self._convert_nodes_to_stages(
            learning_path_nodes, 
            learning_style_weight
        )
        
        return learning_path
    
    def _get_knowledge_level_weight(self, knowledge_level: str) -> float:
        """根据知识水平获取难度权重"""
        weight_map = {
            "beginner": 0.7,
            "intermediate": 1.0,
            "advanced": 1.3
        }
        return weight_map.get(knowledge_level, 1.0)
    
    def _get_learning_style_weight(self, learning_style: str) -> Dict[str, float]:
        """根据学习风格获取内容类型权重"""
        weight_map = {
            "visual": {"video": 1.2, "image": 1.1, "text": 1.0, "interactive": 0.9},
            "auditory": {"audio": 1.2, "video": 1.1, "text": 0.9, "interactive": 1.0},
            "kinesthetic": {"interactive": 1.2, "project": 1.1, "text": 1.0, "video": 0.9}
        }
        return weight_map.get(learning_style, {"text": 1.0})
    
    def _get_interest_weight(self, interests: List[str], subject: str) -> float:
        """根据兴趣匹配度获取权重"""
        if subject in interests:
            return 1.2
        elif any(interest in subject.lower() for interest in [i.lower() for i in interests]):
            return 1.1
        return 1.0
    
    def _get_progress_weight(self, progress: Dict[str, float], subject: str) -> float:
        """根据学习进度获取权重"""
        subject_progress = progress.get(subject, 0.0)
        # 进度越低，权重越高（优先推荐未学习的内容）
        # 使用非线性函数使得进度越低权重增加越快
        return 2.0 - subject_progress if subject_progress < 1.0 else 1.0
    
    def _get_mastered_knowledge_points(self, progress: Dict[str, float]) -> List[int]:
        """
        根据学习进度获取已掌握的知识点
        
        Args:
            progress: 学习进度
            
        Returns:
            已掌握的知识点ID列表
        """
        mastered_points = []
        for subject, progress_value in progress.items():
            if progress_value > 0.8:  # 掌握程度超过80%认为已掌握
                # 在实际应用中，这里需要根据学科和知识点的映射关系来获取具体的知识点ID
                # 目前简化处理
                pass
        return mastered_points
    
    def _find_suitable_path(self, knowledge_graph: Dict, mastered_points: List[int], difficulty_weight: float) -> List[Dict]:
        """
        在知识图谱中查找合适的学习路径
        
        Args:
            knowledge_graph: 知识图谱
            mastered_points: 已掌握的知识点
            difficulty_weight: 难度权重
            
        Returns:
            学习路径节点
        """
        # 从知识图谱中排除已掌握的知识点
        available_nodes = [
            node for node in knowledge_graph["nodes"] 
            if node["id"] not in mastered_points
        ]
        
        # 根据难度权重调整节点选择
        # 简化实现：按难度排序并选择合适的节点
        sorted_nodes = sorted(
            available_nodes, 
            key=lambda x: self._adjust_difficulty_by_weight(x["difficulty"], difficulty_weight)
        )
        
        # 选择前几个节点作为学习路径（最多5个）
        return sorted_nodes[:5]  # 选择前5个节点
    
    def _adjust_difficulty_by_weight(self, difficulty: str, weight: float) -> int:
        """
        根据权重调整难度等级
        
        Args:
            difficulty: 原始难度
            weight: 权重
            
        Returns:
            调整后的难度等级
        """
        difficulty_map = {"easy": 1, "medium": 2, "hard": 3}
        base_difficulty = difficulty_map.get(difficulty, 2)
        # 调整难度，权重越高，越能接受高难度内容
        adjusted_difficulty = base_difficulty / weight
        return int(adjusted_difficulty)
    
    def _convert_nodes_to_stages(self, nodes: List[Dict], learning_style_weight: Dict[str, float]) -> List[LearningPathStage]:
        """
        将知识点节点转换为学习路径阶段
        
        Args:
            nodes: 知识点节点列表
            learning_style_weight: 学习风格权重
            
        Returns:
            学习路径阶段列表
        """
        stages = []
        for i, node in enumerate(nodes):
            # 根据学习风格权重选择合适的资源类型
            preferred_resource_type = max(learning_style_weight, key=learning_style_weight.get)
            
            # 构建学习资源列表
            resources = [preferred_resource_type]
            
            # 添加通用资源类型
            if node["difficulty"] == "easy":
                resources.extend(["article", "video"])
            elif node["difficulty"] == "medium":
                resources.extend(["article", "video", "exercise"])
            else:  # hard
                resources.extend(["article", "video", "exercise", "project"])
            
            # 去重并保持顺序
            unique_resources = []
            for res in resources:
                if res not in unique_resources:
                    unique_resources.append(res)
            
            stage = LearningPathStage(
                stage=i+1,
                topic=node["topic"],
                description=node["description"] or f"学习{node['topic']}相关知识",
                estimated_time=f"{node['estimated_time']}分钟" if node['estimated_time'] else "30分钟",
                resources=unique_resources
            )
            stages.append(stage)
        
        return stages
    
    def update_user_progress(self, user_id: str, subject: str, progress: float) -> bool:
        """
        更新用户学习进度
        同时更新缓存和数据库
        
        Args:
            user_id: 用户ID
            subject: 学科
            progress: 学习进度 (0-1)
            
        Returns:
            是否更新成功
        """
        try:
            # 获取当前用户偏好数据
            user_preference = cache_manager.get_long_term_preference(user_id)
            if not user_preference:
                user_preference = {
                    "knowledge_level": "beginner",
                    "learning_style": "visual",
                    "interests": []
                }
            
            # 更新进度
            if "progress" not in user_preference:
                user_preference["progress"] = {}
            
            user_preference["progress"][subject] = progress
            
            # 根据进度更新用户知识水平
            overall_progress = sum(user_preference["progress"].values()) / len(user_preference["progress"]) if user_preference["progress"] else 0
            if overall_progress < 0.3:
                user_preference["knowledge_level"] = "beginner"
            elif overall_progress < 0.7:
                user_preference["knowledge_level"] = "intermediate"
            else:
                user_preference["knowledge_level"] = "advanced"
            
            # 保存更新后的偏好到缓存和数据库
            return cache_manager.set_long_term_preference(user_id, user_preference)
        except Exception as e:
            print(f"更新用户进度时出错: {e}")
            return False

# 全局推荐系统实例
recommendation_system = LearningPathRecommendation()